AWS IoT Message Brokerに一般のMessage Brokerにあるべき実装がない理由を考えてみた。
こんにちは、せーのです。ラスベガスから東京、札幌と移動してきてちょっと風邪を引きました。 頭がぼーっとしている時に#reinventのYoutubeを見ていてふと疑問に思うことがありました。
AWS IoTのMessage Brokerは色々と実装されていないものがある
AWS IoTが発表になった後ドキュメントを色々読んだりセッションに参加したりしていました。そこでまず学ぶことは「Message Broker」の存在です。 デバイスからのメッセージの受け口になる「Device Gateway」には「Message Broker」というのが働いていて、そこで一般のMQTTメッセージやRestリクエストをさばいたりするわけです。
これは所謂MQTT Brokerの役割を担うわけですが、Device GatewayのMessage Brokerは一般のMQTT Brokerとはこのような違いがあります。
機能 | Amazon IoT Message Broker | Mosquitto |
対応プロトコル | 3.1.1 | 3.1,3.1.1 |
QoS | 0, 1 | 0, 1, 2 |
Will | × | ○ |
Retain | × | ○ |
Payloadサイズ | 128KB | なし |
TLS | ○ | ○ |
WebSocket | × | ○ |
WebSecureSocket | × | ○ |
認証 | AWS アカウントレベル | × |
違い、というより実装として「QoS 2」「Retain」「Will」の機能がないのです。それは何故なのでしょう。ドキュメントにはこれに関しては追求されてはいないのですが、あくまで私の私見として「こうなんじゃないかなー」という考えを書いておきます。
QoS 2がない理由 - スケールしにくいから
QoSとは「Quolity of Service」の略でメッセージが確実にBrokerに届いているかどうかを保証する保証レベルを指します。
QoS 0 - 投げっぱなし
QoS 0は「At Most One」つまり多くても一回、というレベルです。
Publisherがメッセージを投げた結果についてPublisherは責任を持ちません。なのでBrokerに通っているのかどうかは確認のしようがありません。
QoS 1 - 少なくとも一回
QoS 1は「At least One」少なくても一回、というレベルです。
PublisherがBrokerにメッセージを投げるとBrokerはPublisherに対して「PUBACK」という戻り値を返します。Publisherは一定時間にPUBACKが返ってこなければ不通とみなし、もう一度Brokerに対してmessageを投げます。PUBACKが返ってくるまでそれを繰り返すので少なくとも1回は確実にBrokerにメッセージが届くことになります。 一方BrokerはPUBACKを返したらそのままSubscribeに入り、PUBACKを返したらメッセージは削除しますので何かしらの障害があってPUBACKがPublishに届かなかった場合、もう一度PublisherからmessageをBrokerに向けて投げるので、メッセージが重複して届く可能性があるわけです。
QoS 2 - 確実に一回
QoS 2は「Exactly Once」確実に一回、というレベルです。
PublisherがBrokerにメッセージを投げるとBrokerはPublisherに対して「PUBREC」を返します。PublisherはPUBRECを受け取ったら受け取った記しとしてPUBRELをBrokerに返します。BrokerはPUBRELを受け取って初めてSubscribeに入ります。そしてPublisherには「PUBCOMP」を返して終了です。messageはmessage IDを通してBroker内に保存しておく、という仕組みです。
QoS 2はBrokerにメッセージを保存しておく必要がある。
つまり、QoS 2の仕組みを使うとメッセージを一時的にBrokerの中に保存しておく必要があります。これはつまりステートフルな実装となり、Brokerがスケールした時にメッセージがどこのBrokerに入っているのかわからなくなります。ここらへんはSQSが分散キューの為メッセージを名指しして処理するAPIがない、という理由と似ているかと思います。 もしどこのBrokerにメッセージが入っているのかまで確立する実装を行うと相当に複雑な仕組みとなり、レスポンスに影響しそうですね。このような理由からMessage BrokerにはQoS 2がない、と考えます。
Willがない理由 - Shadowがあるから
「Will」というのは「遺言」という意味です。文字通りデバイスが「死んで」しまった時に、予め接続時に登録したメッセージがSubscribeされる、という仕組みです。
AWS IoTには「Shadows」という機能があります。これはデバイスの状態をAWS内に保持して、デバイスがオフライン時にもアプリケーションからの信号をAWSが仲介することによって実現する、というものです。
Willはデバイスが死んだことを知らせる機能です。ですがShadowsがあればそもそも死んだことを知らせる必要がありません。Shadowsに状態変化のデータを入れてオンライン後に同期するのでアプリケーションはデバイスではなくShadowsにデータのアップデートを投げることになります。
Retainがない理由 - スケールしにくいから
「Retain」とは最後にPublishされたメッセージをMQTTサーバーが保持しておき、新しいSubscriberにそのメッセージを渡す機能です。
どうしてAWS IoTのMessage BrokerにはRetainが実装されていないのでしょう。ここはネットを見ていると色々な意見が出ているところですね。 RetainをShadowsに入れておけばいいので、という意見も散見されますが、Shadowsはあくまで「状態」を記録しておくものですので例えば秒単位で変わるセンサーデータを「状態」としてShadowsに保持するのは少し違うかな、と思います。 例えばセンサーデータをShadowsに上書きしていくとします。ShadowsもまたTopicにて表されます。Shadowsの中身を取得するTopicの書き方は
$aws/things/thingName/shadow/get/accepted
となります。つまり、デバイスのデータ全てを取るには
$aws/things/+/shadow/get/accepted
となるでしょうか。これだとデバイスが並列に並んでいるため、例えば地域ごとに違うデバイスがある、等のグループ分けをする時に厳しいです。 やはりセンサーデータは別Topicに整理してpublishした方が取りやすいのではないでしょうか。
となるとやはりRetainを実装しない理由は「RetainメッセージをBroker内に保持しておかなくてはいけないため」ではないでしょうか。先ほどのQoS 2と同じで、RetainをBroker内に保持しておくと、Brokerをスケールしにくくなります。ここが一番の原因と考えます。
まとめ
いかがでしたでしょうか。あくまで私個人の意見ですのでこれが正解、というわけではありませんが、なんとなくこういう理由かな、と考えます。 ぼーっとした中、考えてみました。